﻿/*----------------------------------------------------------------
//  <copyright file="MvcFunctionHandler.cs" company="MicroCloud@151504200868">
//      Copyright © 2020-2024 MicroCloud Corporation, All rights reserved.
//  </copyright>
//  <site>https://gitee.com/chenmm123/microclouds</site>
//  <last-editor>cmm</last-editor>
//  <last-date>2024-03-04 14:42</last-date>
//----------------------------------------------------------------*/

namespace MicroCloud.AspNetCore.Mvc
{
    #region "MVC功能处理器"
    /// <summary>
    /// MVC功能处理器
    /// </summary>
    public class MvcFunctionHandler : FunctionHandlerBase<Function>
    {
        #region "构造函数"
        #region "初始化一个MVC功能处理器的新实例"
        /// <summary>
        /// 初始化一个MVC功能处理器 <see cref="MvcFunctionHandler"/> 的新实例
        /// </summary>
        /// <param name="serviceProvider"></param>
        public MvcFunctionHandler(IServiceProvider serviceProvider)
            : base(serviceProvider)
        { }
        #endregion

        #endregion

        #region "重写方法"
        #region "获取所有功能类型"
        /// <summary>
        /// 获取所有功能类型
        /// </summary>
        /// <returns></returns>
        public override Type[] GetAllFunctionTypes()
        {
            return AssemblyManager.FindTypes(m => m.IsController() && (m.IsPublic || m.IsNestedAssembly));
        }
        #endregion
        #region "查找指定功能的所有功能点方法"
        /// <summary>
        /// 查找指定功能的所有功能点方法  
        /// </summary>
        /// <param name="functionType">功能类型</param>
        /// <returns></returns>
        public override MethodInfo[] GetMethodInfos(Type functionType)
        {
            Check.NotNull(functionType, nameof(functionType));

            List<Type> types = new();
            while (functionType.IsController(true))
            {
                types.AddIfNotExist(functionType);
                functionType = functionType?.BaseType;
                if (functionType == null || functionType.Name == "Controller" || functionType.Name == "ControllerBase")
                {
                    break;
                }
            }

            return types.SelectMany(m => m.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
                .Where(m => !m.IsSpecialName).ToArray();
        }
        #endregion
        #region "重写以实现从功能类型创建功能信息"
        /// <summary>
        /// 重写以实现从功能类型创建功能信息
        /// </summary>
        /// <param name="controllerType">功能类型</param>
        /// <returns></returns>
        protected override Function GetFunction(Type controllerType)
        {
            Check.NotNull(controllerType, nameof(controllerType));

            if (!controllerType.IsController())
            {
                throw new Exception(I18N.T("类型 {0} 不是MVC控制器类型", controllerType.FullName));
            }
            FunctionAccessType accessType = controllerType.HasAttribute<LoggedInAttribute>()
                ? FunctionAccessType.LoggedIn
                : controllerType.HasAttribute<RoleLimitAttribute>()
                    ? FunctionAccessType.RoleLimit
                    : FunctionAccessType.Anonymous;
            Function function = new(controllerType)
            {
                Name = controllerType.GetDescription(),
                Area = GetArea(controllerType),
                Controller = controllerType.Name.Replace("ControllerBase", string.Empty).Replace("Controller", string.Empty),
                IsController = true,
                AccessType = accessType,
            };
            return function;
        }
        #endregion
        #region "重写以实现从方法信息中创建功能信息"
        /// <summary>
        /// 重写以实现从方法信息中创建功能信息
        /// </summary>
        /// <param name="controller">控制器功能信息</param>
        /// <param name="method">方法信息</param>
        /// <returns></returns>
        protected override Function GetFunction(Function controller, MethodInfo method)
        {
            Check.NotNull(controller, nameof(controller));
            Check.NotNull(method, nameof(method));

            FunctionAccessType accessType = method.HasAttribute<LoggedInAttribute>()
                ? FunctionAccessType.LoggedIn
                : method.HasAttribute<AllowAnonymousAttribute>()
                    ? FunctionAccessType.Anonymous
                    : method.HasAttribute<RoleLimitAttribute>()
                        ? FunctionAccessType.RoleLimit
                        : controller.AccessType;
            Function function = new(controller.ControllerType(), method)
            {
                Name = $"{controller.Name}-{method.GetDescription()}",
                Area = controller.Area,
                Controller = controller.Controller,
                Action = method.Name,
                AccessType = accessType,
                IsController = false,
                IsAjax = method.HasAttribute<AjaxOnlyAttribute>(),
            };
            return function;
        }
        #endregion
        #region "重写以实现是否忽略指定方法的功能信息"
        /// <summary>
        /// 重写以实现是否忽略指定方法的功能信息
        /// </summary>
        /// <param name="action">要判断的功能信息</param>
        /// <param name="method">功能相关的方法信息</param>
        /// <param name="functions">已存在的功能信息集合</param>
        /// <returns></returns>
        protected override bool IsIgnoreMethod(Function action, MethodInfo method, IEnumerable<Function> functions)
        {
            Check.NotNull(action, nameof(action));
            Check.NotNull(method, nameof(method));

            if (method.HasAttribute<NonActionAttribute>() || method.HasAttribute<NonFunctionAttribute>())
            {
                return true;
            }

            Function existing = GetFunction(functions, action.Area, action.Controller, action.Action, action.Name);
            //return existing != null && method.HasAttribute<HttpPostAttribute>();
            return existing != null;
        }
        #endregion

        #endregion

        #region "私有静态方法"
        #region "从类型中获取功能的区域信息"
        /// <summary>
        /// 从类型中获取功能的区域信息
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private static string GetArea(MemberInfo type)
        {
            Check.NotNull(type, nameof(type));

            AreaAttribute attribute = type.GetAttribute<AreaAttribute>();
            return attribute?.RouteValue;
        }
        #endregion

        #endregion

    }
    #endregion

}
